#ifndef __HIERARCHICALCONFIGURATION_H__
#define __HIERARCHICALCONFIGURATION_H__

#include <sstream>
#include <string>
#include <vector>

//Forward Declarations
#include "HierarchicalConfigurationNodeVisitor.h"

class HierarchicalConfigurationNode
{
 public:
    HierarchicalConfigurationNode(bool attribute = true,
				  HierarchicalConfigurationNode * parent = 0,
				  const std::string & name = std::string(), 
				  const std::string & value = std::string() ) : m_bAttribute( attribute ),
	m_parentNode( parent ),
	m_name( name ),
	m_value( value )
	{
	}

    ~HierarchicalConfigurationNode()
	{
	    unsigned i;
	    for( i = 0; i < m_children.size(); i++ )
		if( m_children[i] != 0 )
		    delete( m_children[i] );

	    for( i = 0; i < m_attributes.size(); i++ )
		if( m_attributes[i] != 0 )
		    delete( m_attributes[i] );

	}

    // Data Access Methods
    std::vector<HierarchicalConfigurationNode*> subconfigurations( const std::string & key )
	{
	    std::vector<HierarchicalConfigurationNode*> result;
	    std::vector<HierarchicalConfigurationNode*>::iterator it = m_children.begin();
	    while( it != m_children.end() )
		{
		    if( (*it)->name() == key )
			result.push_back( *it );
		    ++it;
		}

	    return( result );
	}

    bool isAttribute() const
	{
	    return( m_bAttribute );
	}

    void setAttribute( bool f )
	{
	    this->m_bAttribute = f;
	}

    std::vector<HierarchicalConfigurationNode*> & attributes()
	{
	    return( m_attributes );
	}

    const std::vector<HierarchicalConfigurationNode*> & attributes() const
	{
	    return( m_attributes );
	}
    
    void addAttribute( HierarchicalConfigurationNode * node )
	{
	    if( node == 0 || node->name().size() == 0 )
		return;
	    
	    node->setAttribute( true );
	    node->setParentNode( this );
	    m_attributes.push_back( node );
	}

    void addAttribute( const std::string & name, const std::string & key )
	{
	    this->addAttribute( new HierarchicalConfigurationNode( true, this, name, key ) );
	}
    
    void removeAttribute( HierarchicalConfigurationNode * node )
    {
	std::vector<HierarchicalConfigurationNode*>::iterator it = m_attributes.begin();
	while( it != m_attributes.end() )
	    {
		if( (*it) == node )
			it = m_attributes.erase( it );
		else
		    ++it;
	    }

	delete( *it );
    }

    void removeAttributes()
	{
	    for( unsigned i = 0; i < m_attributes.size(); i++ )
		delete( m_attributes[i] );
	    m_attributes.clear();
	}

    void removeAttributes( const std::string & name )
	{
	    std::vector<HierarchicalConfigurationNode*>::iterator it = m_attributes.begin();
	    while( it != m_attributes.end() )
		{
		    if( (*it)->name() == name )
			{
			    delete( *it );
			    it = m_attributes.erase( it );
			}
		    else
			++it;
		}
	}
    
    std::vector<HierarchicalConfigurationNode*> & children()
	{
	    return( m_children );
	}

    const std::vector<HierarchicalConfigurationNode*> & children() const
	{
	    return( m_children );
	}

    std::vector<HierarchicalConfigurationNode*> children( const std::string & name )
	{
	    std::vector<HierarchicalConfigurationNode*> result;
	    unsigned i;
	    for( i = 0; i < m_children.size(); i++ )
		if( m_children[i]->name() == name )
		    result.push_back( m_children[i] );

	    return( result );
	}

    void addChild( const std::string & name, const std::string & value )
	{
	    this->addChild( new HierarchicalConfigurationNode( false, this, name, value ) );
	}

    void addChild( HierarchicalConfigurationNode * node )
	{
	    if( node == 0 || node->name().size() == 0 )
		return;

	    node->setParentNode( this );
	    node->setAttribute( false );
	    m_children.push_back(  node );
	}

    void removeChild( HierarchicalConfigurationNode * node )
	{
	    std::vector<HierarchicalConfigurationNode*>::iterator it = m_children.begin();
	    while( it != m_children.end() )
		{
		    if( (*it) == node )
			{
			    delete( *it );
			    it = m_children.erase( it );
			}
		    else
			++it;
		}	

	    delete node;
	}

    void removeChildren()
	{
	    for( unsigned i = 0; i < m_children.size(); i++ )
		delete( m_children[i] );
	    
	    m_children.clear();
	}

    void removeChildren( const std::string & name )
	{
	    std::vector<HierarchicalConfigurationNode*>::iterator it = m_children.begin();
	    while( it != m_children.end() )
		{
		    if( (*it)->name() == name )
			{
			    delete( *it );
			    it = m_children.erase( it );
			}
		    else
			++it;
		}	    
	}

    HierarchicalConfigurationNode * parentNode()
	{
	    return( m_parentNode );
	}

    const HierarchicalConfigurationNode * parentNode() const
	{
	    return( m_parentNode );
	}
    
    void setParentNode( HierarchicalConfigurationNode * parentNode )
	{
	    m_parentNode = parentNode;
	}

    const std::string & name() const
	{
	    return( m_name );
	}

    void setName( const std::string & name )
	{
	    m_name = name;
	}

    const std::string & value() const
	{
	    return( m_value );
	}

    template <typename T>
	T castValue( const T & defaultValue )
	{
	    if( m_value.size() == 0 )
		return( defaultValue );

	    std::stringstream stream( m_value );
	    T result; stream >> result;
	    return( result );
	}

    void setValue( const std::string & value )
	{
	    m_value = value;
	}

    void visit( HierarchicalConfigurationNodeVisitor * visitor )
	{
	    if( visitor == 0 )
		return;
	    
	    visitor->visitBeforeChildren( this );

	    if( visitor->terminate() )
		return;

	    unsigned i;
	    // Iterating attributes
	    for( i = 0; i < m_attributes.size(); i++ )
		{
		    m_attributes[i]->visit( visitor );
		    if( visitor->terminate() )
			return;
		}
	    // Iterating children
	    for( i = 0; i < m_children.size(); i++ )
		{
		    m_children[i]->visit( visitor );
		    if( visitor->terminate() )
			return;
		}

	    visitor->visitAfterChildren( this );	
	}
    
 protected:
    bool m_bAttribute;
    std::string m_name, m_value;

    HierarchicalConfigurationNode * m_parentNode;

    std::vector<HierarchicalConfigurationNode*> m_attributes;
    std::vector<HierarchicalConfigurationNode*> m_children;
};


#endif // __HIERARCHICALCONFIGURATION_H__
